/*
 * Copyright (C) 2000 - 2024 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception.  You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "https://www.silverpeas.org/legal/floss_exception.html"
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package org.silverpeas.core.contribution.attachment;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.silverpeas.core.annotation.Service;
import org.silverpeas.core.contribution.attachment.model.SimpleDocument;
import org.silverpeas.kernel.bundle.ResourceLocator;
import org.silverpeas.core.util.ServiceProvider;
import org.silverpeas.kernel.bundle.SettingBundle;
import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.core.util.file.FileRepositoryManager;
import org.silverpeas.kernel.logging.SilverLogger;

import java.io.File;
import java.io.IOException;

/**
 * A processor of documents with 3D images or CAD for the Actify tool.
 * The CAD documents imported in Silverpeas are treated by this processor so that Actify can convert
 * them into the 3D format. This 3D documents produced by Actify are then imported by Silverpeas.
 *
 * @author mmoquillon
 */
@Service
public class ActifyDocumentProcessor {

  private static final SettingBundle settings =
      ResourceLocator.getSettingBundle("org.silverpeas.util.attachment.Attachment");
  private final SilverLogger logger = SilverLogger.getLogger(this);

  /**
   * Is the support of CAD documents processing is enabled? If it is enabled, the Actify tool must
   * be installed, well configured and ran on the server.
   *
   * @return true if Actify is running and ready to work with Silverpeas. False otherwise.
   */
  public static boolean isActifySupportEnabled() {
    return settings.getBoolean("ActifyPublisherEnable", false);
  }

  /**
   * Gets the CRON instruction to schedule the import of 3D documents generated by Actify into
   * Silverpeas.
   *
   * @return a CRON rule.
   */
  public static String getCRONForActifyImport() {
    return settings.getString("ScheduledProcessActify");
  }

  /**
   * Gets the CRON instruction to schedule the purge of CAD documents scanned by Actify to generate
   * the 3D documents.
   *
   * @return a CRON rule.
   */
  public static String getCRONForActifyPurge() {
    return settings.getString("ScheduledPurgeActify");
  }

  /**
   * Gets the absolute path of the directory into which the CAD documents are uploaded and from
   * which Actify scans for files to convert in 3D format.
   *
   * @return the absolute path of the directory containing the CAD documents to convert by Actify.
   */
  public static String getActifySourcePath() {
    return FileRepositoryManager.getTemporaryPath() + settings.getString("ActifyPathSource");
  }

  /**
   * Gets the absolute path of the directory containing the 3D documents generated by Actify and to
   * import in Silverpeas.
   *
   * @return the absolute path of the directory containing the 3D documents to import in Silverpeas.
   */
  public static String getActifyResultPath() {
    return FileRepositoryManager.getTemporaryPath() + settings.getString("ActifyPathResult");
  }

  /**
   * Gets the CAD file extensions supported by Actify.
   *
   * @return an array of CAD extensions supported by Actify.
   */
  public static String[] getSupportedCADExtensions() {
    String extensions = settings.getString("Actify3dFiles");
    if (StringUtil.isDefined(extensions)) {
      return extensions.split(",");
    }
    return new String[0];
  }

  /**
   * Gets the delay before the import of a 3D document. The delay is used to ensure the document is
   * completely generated by Actify.
   *
   * @return the delay in minutes.
   */
  public static int getDelayBeforeImport() {
    return Integer.parseInt(settings.getString("DelayBeforeProcess"));
  }

  /**
   * Gets the delay before the purge of CAD documents scanned by Actify. The delay is used to ensure
   * the CAD documents are taken in charge by Actify before removing them. completely generated by
   * Actify.
   *
   * @return the delay in minutes.
   */
  public static int getDelayBeforePurge() {
    return Integer.parseInt(settings.getString("DelayBeforePurge"));
  }

  /**
   * Is the specified file is a CAD document supported by Actify?
   *
   * @param fileName the file name.
   * @return true if the file is a CAD document supported by Actify. False otherwise.
   */
  public static boolean isCADDocumentSupported(String fileName) {
    String[] extensions = getSupportedCADExtensions();
    String type = FileRepositoryManager.getFileExtension(fileName);
    // 3d native file?
    boolean fileForActify = false;
    for (int i = 0; i < extensions.length && !fileForActify; i++) {
      fileForActify = type.equalsIgnoreCase(extensions[i]);
    }
    return fileForActify;
  }

  /**
   * Gets an instance of {@code ActifyDocumentProcessor}.
   *
   * @return an ActifyDocumentProcessor instance.
   */
  public static ActifyDocumentProcessor getProcessor() {
    return ServiceProvider.getService(ActifyDocumentProcessor.class);
  }

  /**
   * Processes the specified CAD document by placing it in the location expected by Actify.
   *
   * @param document a CAD document.
   * @throws IOException if an error occurs while putting the document into the expected location.
   */
  public void process(final SimpleDocument document) throws IOException {
    if (isActifySupportEnabled()) {
      String componentId = document.getPk().getInstanceId();
      String id = document.getForeignId();
      String fileName = document.getFilename();
      if (isCADDocumentSupported(fileName)) {
        logger.debug("CAD document supported by Actify detected: {0}", fileName);
        String dirPrefix = document.isVersioned() ? "v_" : "a_";
        String dirDestName = dirPrefix + componentId + "_" + id;
        String actifyWorkingPath = getActifySourcePath() + File.separatorChar + dirDestName;
        File destDir = new File(actifyWorkingPath);
        if (!destDir.exists()) {
          FileUtils.forceMkdir(destDir);
        }
        String normalizedFileName = FilenameUtils.normalize(fileName);
        if (normalizedFileName == null) {
          normalizedFileName = FilenameUtils.getName(fileName);
        }
        String destFile = actifyWorkingPath + File.separatorChar + normalizedFileName;
        FileRepositoryManager.copyFile(document.getAttachmentPath(), destFile);
      }
    }
  }

  protected ActifyDocumentProcessor() {
    prepareActifyDirectories();
  }

  private void prepareActifyDirectories() {
    try {
      if (isActifySupportEnabled()) {
        File dir = new File(getActifySourcePath());
        if (!dir.exists()) {
          FileUtils.forceMkdir(dir);
        }
        dir = new File(getActifyResultPath());
        if (!dir.exists()) {
          FileUtils.forceMkdir(dir);
        }
      }
    } catch (IOException e) {
      logger.error(e.getMessage(), e);
    }
  }
}
